/*
 * ObjetoReflexion.java	
 *
 * Copyright 2008 Universidad Francisco de Paula Santander (UFPS).
 * Todos los Derechos Reservados.
 * Creado el 07/10/08, 12:30:38 AM
 */
package com.ufps.cuatro.modelo.analizador;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Observable;

import com.ufps.cuatro.modelo.representacion.CustomObjetoReflexion;

/**
 * <i><b>ObjetoReflexion:</b></i> <p>Esta Clase permite almacenar un objeto
 * obtenido por medio de la técnica de Reflexión, el objeto contenido
 * por lo general es un tipo class el cual representa un tipo de dato
 * analizado en el archivo .jar, pero en ocasiones puede ser un método ó un
 * atributo de una clase.</p>
 *
 * @author  Carlos A. Torres C. - Dolly E. Guerrero. <https://code.google.com/p/tesis4dor/>
 * @version 1.0 07/10/08
 * @see Serializable 
 * @see Observable
 */
public class ObjetoReflexion extends Observable implements Serializable{
    private static final long serialVersionUID = 1033084238350931841L;

    private Object obj;    
    private String strNombre = "";
    private String toGenericString = "";
    private transient Class<?> objClass;   
    private boolean abstractClass = false;
    private CustomObjetoReflexion objCustomObjetoReflexion;

    /**
     * Constructor por defecto.
     */
    public ObjetoReflexion() {
    }

    /**
     * Constructor que recibe un obj.
     * @param obj Propiedad de una Clase del Modelo Analizado.
     */
    public ObjetoReflexion(Object obj) {
        this.obj = obj;
        if(obj instanceof Method){
            Method objMetodo = (Method) obj;
            strNombre = objMetodo.getName();
            toGenericString = objMetodo.toGenericString();
        }
        else if(obj instanceof Field){
            Field objAtributo = (Field) obj;
            strNombre = objAtributo.getName();
            toGenericString = objAtributo.toGenericString();
        }
        else if(obj instanceof Constructor){
            Constructor objConstructor = (Constructor) obj;
            strNombre = objConstructor.getName();
            toGenericString = objConstructor.toGenericString();
        }
        else if(obj != null){
            strNombre = obj.getClass().getSimpleName();
            toGenericString = obj.getClass().getCanonicalName();
        }
        else{
            strNombre = "Error";
        }
    }

    /**
     * Contructor que un Objeto Class que Representa una Clase del Modelo Analizado.
     * @param objClass Objeto Class que Representa una Clase del Modelo Analizado.
     */
    public ObjetoReflexion(Class<?> objClass) {
        this.objClass = objClass;        
        if(objClass != null){
            strNombre = objClass.getSimpleName();
        }
    }

    @Override
    public synchronized String toString() {                
        if(obj != null || objClass != null) {
            return strNombre;
        }
        return "No Disponible";
    }

    /**
     * Devuelve el <code>Object</code> que representa una Propiedad de una Clase
     * del Modelo Analizado.
     * @return <code>Object</code> que representa una Propiedad de una Clase
     * del Modelo Analizado.
     */
    public Object getObj() {
        return obj;
    }

    /**
     * Establece el <code>Object</code> que representa una Propiedad de una Clase
     * del Modelo Analizado.
     * @param obj @DefinicionParametro
     */
    public void setObj(Object obj) {
        this.obj = obj;        
    }

    /**
     * Devuelve el Objeto Class que Representa una Clase del Modelo Analizado.
     * @return Objeto Class que Representa una Clase del Modelo Analizado.
     */
    public Class<?> getObjClass() {
        return objClass;
    }

    /**
     * Establece el Objeto Class que Representa una Clase del Modelo Analizado.
     * @param objClass Objeto Class que Representa una Clase del Modelo Analizado.
     */
    public void setObjClass(Class<?> objClass) {
        this.objClass = objClass;
    }

    /**
     * Devuelve el Nombre de la Propiedad (Encapsulada) de una Clase del 
     * Modelo Analizado.
     * @return Nombre de la Propiedad (Encapsulada) de una Clase del 
     * Modelo Analizado.
     */
    public String getStrNombre() {
        return strNombre;
    }

    /**
     * Establece el Nombre de la Propiedad (Encapsulada) de una Clase del 
     * Modelo Analizado.
     * @param strNombre Nombre de la Propiedad (Encapsulada) de una Clase del 
     * Modelo Analizado.
     */
    public void setStrNombre(String strNombre) {
        this.strNombre = strNombre;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof ObjetoReflexion){
            ObjetoReflexion objR = (ObjetoReflexion) obj;
            return this.toString().equals(objR.toString());
        }
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 67 * hash + (this.obj != null ? this.obj.hashCode() : 0);
        hash = 67 * hash + (this.strNombre != null ? this.strNombre.hashCode() : 0);
        return hash;
    }    

//    @Override
//    public Object clone() {
//        ObjetoReflexion objClon = null;
//        try {
//            //Primero se Clona la Referencia Local
//            objClon = (ObjetoReflexion) super.clone();
//        } catch (CloneNotSupportedException ex) {
//            Logger.getLogger(ObjetoReflexion.class.getName()).log(Level.SEVERE, null, ex);
//        }
//        //Ahora se hace la Clonación Profunda
//        if(strNombre != null){
//            ((ObjetoReflexion)objClon).setStrNombre(new String(strNombre.toCharArray()));
//        }
//        if(objClass != null){
//            ((ObjetoReflexion)objClon).setObjClass(objClass);
//        }
//        if(obj != null){
//            ((ObjetoReflexion)objClon).setObj(obj);
//        }
//        return objClon;
//    }

    public boolean isAbstractClass() {
        return abstractClass;
    }

    public void setAbstractClass(boolean abstractClass) {
        this.abstractClass = abstractClass;
    }

    public String getToGenericString() {
        return toGenericString;
    }

    public CustomObjetoReflexion getObjCustomObjetoReflexion() {
        return objCustomObjetoReflexion;
    }

    public void setObjCustomObjetoReflexion(CustomObjetoReflexion objCustomObjetoReflexion) {
        this.objCustomObjetoReflexion = objCustomObjetoReflexion;
    }
}
